package resourcename

import (
	"encoding/json"
	"fmt"
	"strings"

	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/bson/bsontype"
)

type (
	ResourceName struct {
		Partition  string
		Service    string
		Region     string
		AccountID  string
		ProjectID  string
		ResourceID string
	}
	IsolationContext struct {
		Partition string
		Service   string
		Region    string
		AccountID string
		ProjectID string
	}
)

func (r *ResourceName) UnmarshalJSON(data []byte) error {
	var structure string

	if err := json.Unmarshal(data, &structure); err != nil {
		return err
	}

	resource, err := ParseResourceName(structure)

	if err != nil {
		return fmt.Errorf("resource name cannot parse %w", err)

	}

	*r = resource
	return nil
}

func (r ResourceName) MarshalJSON() ([]byte, error) {

	return json.Marshal(r.String())
}

func (r ResourceName) MarshalBSONValue() (bsontype.Type, []byte, error) {

	return bson.MarshalValue(r.String())
}

func (r *ResourceName) UnmarshalBSONValue(t bsontype.Type, data []byte) error {
	value := bson.RawValue{Type: t, Value: data}

	result := value.StringValue()

	resource, err := ParseResourceName(result)

	if err != nil {
		return fmt.Errorf("resource name cannot parse %w", err)

	}
	*r = resource
	return nil
}

func ParseResourceName(str string) (ResourceName, error) {
	split := strings.Split(str, ":")
	if len(split) < 7 {
		return ResourceName{}, fmt.Errorf("expected at least 7 parts with delimeter ':', but was '%d'", len(split))
	}

	return ResourceName{
		Partition:  split[1],
		Service:    split[2],
		Region:     split[3],
		AccountID:  split[4],
		ProjectID:  split[5],
		ResourceID: split[6],
	}, nil
}

func (rn ResourceName) String() string {
	return fmt.Sprintf("rn:%s:%s:%s:%s:%s:%s", rn.Partition, rn.Service, rn.Region, rn.AccountID, rn.ProjectID, rn.ResourceID)
}

func (rn ResourceName) StringWithDelimeter(delimeter rune) string {
	return strings.Join([]string{"rn", rn.Partition, rn.Service, rn.Region, rn.AccountID, rn.ProjectID, rn.ResourceID}, string(delimeter))

}

func (rn ResourceName) ToIsolationContext() IsolationContext {
	return IsolationContext{
		Partition: rn.Partition,
		Service:   rn.Service,
		Region:    rn.Region,
		AccountID: rn.AccountID,
		ProjectID: rn.ProjectID,
	}
}

func ParseIsolationContext(str string) (IsolationContext, error) {
	split := strings.Split(str, ":")
	if len(split) < 7 {
		return IsolationContext{}, fmt.Errorf("expected at least 7 parts with delimeter ':', but was '%d'", len(split))
	}

	return IsolationContext{
		Partition: split[1],
		Service:   split[2],
		Region:    split[3],
		AccountID: split[4],
		ProjectID: split[5],
	}, nil
}

func (ic IsolationContext) String() string {
	return fmt.Sprintf("rn:%s:%s:%s:%s:%s", ic.Partition, ic.Service, ic.Region, ic.AccountID, ic.ProjectID)
}

func (ic IsolationContext) StringWithDelimeter(delimeter rune) string {
	return strings.Join([]string{"rn", ic.Partition, ic.Service, ic.Region, ic.AccountID, ic.ProjectID}, string(delimeter))

}
